﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using PaintDotNet;
using PaintDotNet.Effects;

namespace LibFiltr
{
    public class SeparableFilter
    {
        protected int _radius_h, _radius_v;
        protected double[] _kernel_h, _kernel_v;

        public SeparableFilter(int radius)
        {
            _radius_h = _radius_v = radius;
            _kernel_h = new double[SizeHorizontal];
            _kernel_v = new double[SizeVertical];
        }

        public SeparableFilter(int radius_h, int radius_v)
        {
            _radius_h = radius_h;
            _radius_v = radius_v;
            _kernel_h = new double[SizeHorizontal];
            _kernel_v = new double[SizeVertical];
        }

        public int SizeHorizontal
        {
            get { return _radius_h * 2 + 1; }
        }

        public int SizeVertical
        {
            get { return _radius_v * 2 + 1; }
        }
        

        public void Print()
        {
            for (int i = 0; i < SizeHorizontal; i++)
                Console.Write(_kernel_h[i]);
            Console.WriteLine();
            for (int i = 0; i < SizeVertical; i++)
                Console.Write(_kernel_v[i]);
        }

        public void FilterHorizontal(Surface dst, Surface src, Rectangle selection, Rectangle rect)
        {
            ColorBgra CurrentPixel;
            // horizontal step
            for (int y = rect.Top; y < rect.Bottom; y++)
            {
                for (int x = rect.Left; x < rect.Right; x++)
                {
                    CurrentPixel = src[x, y];
                    double sumR = 0, sumG = 0, sumB = 0;
                    for (int i = -_radius_h; i <= _radius_h; i++)
                    {
                        int ipos = Math.Max(x + i, selection.Left);
                        ipos = Math.Min(ipos, selection.Right - 1);
                        sumR += src[ipos, y].R * _kernel_h[i + _radius_h];
                        sumG += src[ipos, y].G * _kernel_h[i + _radius_h];
                        sumB += src[ipos, y].B * _kernel_h[i + _radius_h];
                    }
                    CurrentPixel.R = (byte)Math.Round(sumR);
                    CurrentPixel.G = (byte)Math.Round(sumG);
                    CurrentPixel.B = (byte)Math.Round(sumB);
                    dst[x, y] = CurrentPixel;
                }
            }
        }

        public void FilterVertical(Surface dst, Surface src, Rectangle selection, Rectangle rect)
        {
            ColorBgra CurrentPixel;
            // vertical step
            for (int y = rect.Top; y < rect.Bottom; y++)
            {
                for (int x = rect.Left; x < rect.Right; x++)
                {
                    CurrentPixel = src[x, y];
                    double sumR = 0, sumG = 0, sumB = 0;
                    for (int i = -_radius_v; i <= _radius_v; i++)
                    {
                        int ipos = Math.Max(y + i, selection.Top);
                        ipos = Math.Min(ipos, selection.Bottom - 1);
                        sumR += src[x, ipos].R * _kernel_v[i + _radius_v];
                        sumG += src[x, ipos].G * _kernel_v[i + _radius_v];
                        sumB += src[x, ipos].B * _kernel_v[i + _radius_v];
                    }
                    CurrentPixel.R = (byte)Math.Round(sumR);
                    CurrentPixel.G = (byte)Math.Round(sumG);
                    CurrentPixel.B = (byte)Math.Round(sumB);
                    dst[x, y] = CurrentPixel;
                }
            }
        }
    }
}
